package top.techqi.view.viewpager2

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.DiffUtil
import androidx.viewpager2.adapter.FragmentStateAdapter

abstract class DataFragmentStateAdapter<T> : FragmentStateAdapter {
    protected val data = ArrayList<T>()

    constructor(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
            super(fragmentManager, lifecycle)

    constructor(activity: FragmentActivity) : super(activity)
    constructor(fragment: Fragment) : super(fragment)

    override fun getItemCount(): Int = data.size

    override fun getItemId(position: Int): Long {
        return data[position].hashCode().toLong()
    }

    override fun containsItem(itemId: Long): Boolean {
        return data.any { it.hashCode().toLong() == itemId }
    }

    open fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
        return oldItem == newItem
    }

    open fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
        return oldItem == newItem
    }

    fun commit(data: List<T>) {
        val dr = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
            val oldList = this@DataFragmentStateAdapter.data
            val newList = data

            override fun getOldListSize(): Int = oldList.size
            override fun getNewListSize(): Int = newList.size

            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                val old = oldList.getOrNull(oldItemPosition) ?: return false
                val new = newList.getOrNull(newItemPosition) ?: return false
                return areItemsTheSame(old, new)
            }

            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                val old = oldList.getOrNull(oldItemPosition) ?: return false
                val new = newList.getOrNull(newItemPosition) ?: return false
                return areContentsTheSame(old, new)
            }
        })

        this.data.clear()
        this.data.addAll(data)
        dr.dispatchUpdatesTo(this)
    }
}
